package org.jsola.contract.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.jsola.common.BeanKit;
import org.jsola.common.StrKit;
import org.jsola.contract.common.ExampleKit;
import org.jsola.contract.constant.AccountType;
import org.jsola.contract.constant.ContractConstants;
import org.jsola.contract.constant.SignMethod;
import org.jsola.contract.dao.ICategoryDAO;
import org.jsola.contract.dto.*;
import org.jsola.contract.entity.*;
import org.jsola.contract.provider.ILogProviderService;
import org.jsola.contract.query.CategoryQuery;
import org.jsola.contract.service.*;
import org.jsola.contract.vo.*;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.log.constant.ActionType;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.HtmlUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 合同类型
 *
 * @author JanusMix
 */
@Slf4j
@Service("contractCategoryServiceImpl")
public class CategoryServiceImpl implements ICategoryService {

    @Autowired
    private ICategoryDAO categoryDAO;
    @Autowired
    private IContractService contractService;
    @Autowired
    private IContractGroupService contractGroupService;
    @Autowired
    private ITemplateService templateService;
    @Autowired
    private ITemplateVariableService templateVariableService;
    @Autowired
    private ISealPositionService sealPositionService;
    @Autowired
    @Lazy
    private ISealService sealService;

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public CategoryVO save(CategoryAddDTO categoryAddDTO, TokenUser tokenUser) {

        List<CategoryDO> categoryDOList = selectBySubjectIdAndNames(categoryAddDTO.getSubjectId()
                , "待添加", Collections.singletonList(categoryAddDTO.getName()), tokenUser);
        ParamException.isTrue(CollectionUtils.isEmpty(categoryDOList), "已有同名合同模板");
        // 转DO
        CategoryDO categoryDO = categoryAddDTO.to(CategoryDO.class);
        if (SignMethod.PERSON_ONLY.getValue().equals(categoryDO.getSignType())) {
            categoryDO.setEnterpriseSealId(null);
        }
        String name = categoryDO.getName();
        name = name.replaceAll("&nbsp;", " ");
        categoryDO.setName(HtmlUtils.htmlUnescape(name));
        // 保存
        categoryDO = save(categoryDO, tokenUser.getSiteId(), tokenUser.getUserId());
        CategoryVO categoryVO = categoryDO.to(CategoryVO.class);
        // 同时新增一个该合同类型的模板
        TemplateAddDTO templateAddDTO = new TemplateAddDTO();
        templateAddDTO.setCategoryId(categoryDO.getId());
        templateAddDTO.setName(categoryDO.getName());
        templateAddDTO.setTotalPage(1);
        templateService.save(templateAddDTO, tokenUser);
        try {
            // 保存log日志
            ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
            if (logProviderService == null) {
                log.error("logProviderService is null");
                return categoryVO;
            }
            logProviderService.log(categoryDO.getName() + "由管理员" + tokenUser.getUserName() +
                            " 新建合同模板", ActionType.SAVE.getValue(), "Category"
                    , categoryDO.getId() + "", categoryDO.getSubjectId(), tokenUser);
        } catch (Exception e) {
            log.error("contract保存日志出错了", e);
        }

        return categoryVO;
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public CategoryVO saveNoLogic(CategoryAddDTO categoryAddDTO, TokenUser tokenUser) {

        List<CategoryDO> categoryDOList = selectBySubjectIdAndNames(categoryAddDTO.getSubjectId()
                , "待添加", Collections.singletonList(categoryAddDTO.getName()), tokenUser);
        ParamException.isTrue(CollectionUtils.isEmpty(categoryDOList), "已有同名合同模板");
        // 转DO
        CategoryDO categoryDO = categoryAddDTO.to(CategoryDO.class);
        if (SignMethod.PERSON_ONLY.getValue().equals(categoryDO.getSignType())) {
            categoryDO.setEnterpriseSealId(null);
        }
        String name = categoryDO.getName();
        name = name.replaceAll("&nbsp;", " ");
        categoryDO.setName(HtmlUtils.htmlUnescape(name));
        // 保存
        categoryDO = save(categoryDO, tokenUser.getSiteId(), tokenUser.getUserId());
        try {
            // 保存log日志
            ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
            if (logProviderService == null) {
                log.error("logProviderService is null");
                return categoryDO.to(CategoryVO.class);
            }
            logProviderService.log(categoryDO.getName() + "由管理员" + tokenUser.getUserName() +
                            " 新建合同模板", ActionType.SAVE.getValue(), "Category"
                    , categoryDO.getId() + "", categoryDO.getSubjectId(), tokenUser);
        } catch (Exception e) {
            log.error("contract保存日志出错了", e);
        }
        return categoryDO.to(CategoryVO.class);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public List<CategoryVO> batchSave(List<CategoryAddDTO> categoryAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(categoryAddDTOList)) {
            return null;
        }
        List<CategoryDO> categoryDOList = categoryAddDTOList
                .parallelStream()
                .map(categoryAddDTO -> {
                    CategoryDO categoryDO = categoryAddDTO.to(CategoryDO.class);
                    categoryDO.preInsert(tokenUser.getUserId());
                    categoryDO.setSiteId(tokenUser.getSiteId());
                    return categoryDO;
                }).collect(Collectors.toList());
        categoryDAO.insertListAndSetId(categoryDOList);
        return categoryDOList
                .parallelStream()
                .map(categoryDO -> categoryDO.to(CategoryVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int update(CategoryUpdateDTO categoryUpdateDTO, TokenUser tokenUser) {
        ParamException.notNull(categoryUpdateDTO.getName(), "待添加分组下的模板已全部失效，请重新选择");
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andEqualTo("subjectId", categoryUpdateDTO.getSubjectId())
                .andEqualTo("name", categoryUpdateDTO.getName())
                .andNotEqualTo("id", categoryUpdateDTO.getId());
        List<CategoryDO> categoryDOList = categoryDAO.selectByExample(example);

        ParamException.isTrue(CollectionUtils.isEmpty(categoryDOList), "已有同名合同模板");
        //转DO
        CategoryDO categoryDO = categoryUpdateDTO.to(CategoryDO.class);
        //关键字段的修改不能有待签署的合同
//        CategoryDO originCategory = this.selectDOById(categoryDO.getId(), tokenUser.getSiteId());
//        boolean isSignTypeChange = StrKit.isNotEmpty(categoryDO.getSignType()) && !categoryDO.getSignType().equals(originCategory.getSignType());
//        boolean isEnterpriseSealIdChange = StrKit.isNotEmpty(categoryDO.getEnterpriseSealId()) && !categoryDO.getEnterpriseSealId().equals(originCategory.getEnterpriseSealId());
//        boolean isExpireDaysChange = StrKit.isNotEmpty(categoryDO.getExpireDays()) && !categoryDO.getExpireDays().equals(originCategory.getExpireDays());
//        if (isSignTypeChange || isEnterpriseSealIdChange || isExpireDaysChange) {
//            if (this.isCategoryHasContractSigning(originCategory, tokenUser.getSiteId())) {
//                throw new ParamException("合同类型【" + categoryDO.getName() + "】下有正在签署中的合同，请等待签署完毕后在进行修改");
//            }
//        }
        String name = categoryDO.getName();
        name = name.replaceAll("&nbsp;", " ");
        categoryDO.setName(HtmlUtils.htmlUnescape(name));
        //根据主键更新，只更新非null值
        int updateByIdSelective = updateByIdSelective(categoryDO, tokenUser.getSiteId(), tokenUser.getUserId());
        ParamException.isTrue(updateByIdSelective > 0, "更新失败了，请刷新页面后重试");
        // 单方签署时更新印章Id为null
        if (SignMethod.PERSON_ONLY.getValue().equals(categoryDO.getSignType())) {
            CategoryDO originCategory = selectDOById(categoryDO.getId(), tokenUser.getSiteId());
            originCategory.setEnterpriseSealId(null);
            updateById(originCategory, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        CategoryDO newCategoryDO = selectDOById(categoryDO.getId(), tokenUser.getSiteId());
        try {
            // 保存log日志
            ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
            if (logProviderService == null) {
                log.error("logProviderService is null");
                return updateByIdSelective;
            }
            logProviderService.log(newCategoryDO.getName() + "由管理员" + tokenUser.getUserName() +
                            " 修改合同模板", ActionType.UPDATE.getValue(), "Category"
                    , newCategoryDO.getId() + "", newCategoryDO.getSubjectId(), tokenUser);
        } catch (Exception e) {
            log.error("contract保存日志出错了", e);
        }
        return updateByIdSelective;
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... categoryIds) {
        List<CategoryDO> categoryDOList = new ArrayList<>();
        for (Long categoryId : categoryIds) {
            CategoryDO categoryDO = this.selectDOById(categoryId, tokenUser.getSiteId());
            if (categoryDO == null) {
                continue;
            }
            categoryDOList.add(categoryDO);
            if (this.isCategoryHasContractSigning(categoryDO, tokenUser.getSiteId())) {
                throw new ParamException("合同类型【" + categoryDO.getName() + "】下有正在签署中的合同，请等待签署完毕后在进行删除");
            }
        }
        int logicalDeleteByIds = logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) categoryIds);
        try {
            for (CategoryDO categoryDO : categoryDOList) {
                // 保存log日志
                ILogProviderService logProviderService = BeanKit.getBean(ILogProviderService.class);
                if (logProviderService == null) {
                    log.error("logProviderService is null");
                    return logicalDeleteByIds;
                }
                logProviderService.log(categoryDO.getName() + "由管理员" + tokenUser.getUserName() +
                                " 删除合同模板", ActionType.DELETE.getValue(), "Category"
                        , categoryDO.getId() + "", categoryDO.getSubjectId(), tokenUser);
            }
        } catch (Exception e) {
            log.error("contract保存日志出错了", e);
        }
        return logicalDeleteByIds;
    }


    @Override
    public CategoryVO selectById(Long categoryId, String siteId) {
        CategoryDO categoryDO = selectDOById(categoryId, siteId);
        if (categoryDO == null) {
            return null;
        }
        CategoryVO categoryVO = categoryDO.to(CategoryVO.class);
        //如果有企业签署
        if (!SignMethod.PERSON_ONLY.getValue().equals(categoryDO.getSignType())) {
            // 查询印章是否失效
            SealVO sealVO = sealService.selectById(categoryDO.getEnterpriseSealId(), siteId);
            // 印章不存在或未认证或所属业务id不同 返回印章信息为空
            if (sealVO == null || sealVO.getStatus() != 1 || !categoryDO.getSubjectId().equals(sealVO.getSubjectId())) {
                categoryVO.setEnterpriseSealId(null);
            } else {
                categoryVO.setEnterpriseName(sealVO.getRoundText());
            }
        }
        return categoryVO;
    }

    @Override
    public List<CategoryDO> selectByIds(List<Long> categoryIds) {
        if (CollectionUtils.isEmpty(categoryIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(CategoryDO.class);
        example.and()
                .andIn("id", categoryIds);
        return categoryDAO.selectByExample(example);
    }

    @Override
    public List<CategoryListVO> select(CategoryQuery categoryQuery, String siteId) {
        List<CategoryDO> categoryDOList = selectDO(categoryQuery, siteId);
        if (CollectionUtils.isEmpty(categoryDOList)) {
            return categoryDOList == null ? null : new ArrayList<>();
        }
        return categoryDOList.stream()
                .map(categoryDO -> categoryDO.to(CategoryListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public List<ContractGroupListVO> selectTreeBySubjectId(String subjectId, String name, TokenUser tokenUser) {
        // 查询公司下的分组
        List<ContractGroupDO> contractGroupDOList = contractGroupService.selectBySubjectId(subjectId, tokenUser);
        if (CollectionUtils.isEmpty(contractGroupDOList)) {
            return new ArrayList<>();
        }
        // 查询公司下合同类型 并按分组分组
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("valid", true);
        List<CategoryDO> categoryDOList = categoryDAO.selectByExample(example);
        Map<Long, List<CategoryListVO>> groupIdListMap = categoryDOList.parallelStream().map(categoryDO
                -> categoryDO.to(CategoryListVO.class)).collect(Collectors.groupingBy(CategoryListVO::getGroupId));
        // 树状 分组-类型
        return contractGroupDOList.parallelStream().map(contractGroupDO -> {
            ContractGroupListVO contractGroupListVO = contractGroupDO.to(ContractGroupListVO.class);
            List<CategoryListVO> categoryListVOList = groupIdListMap.get(contractGroupDO.getId());
            if (CollectionUtils.isEmpty(categoryListVOList)) {
                return null;
            }
            for (CategoryListVO categoryListVO : categoryListVOList) {
                categoryListVO.setGroupName(contractGroupDO.getName());
            }
            if (name != null) {
                if (contractGroupDO.getName() == null) {
                    return null;
                }
                if (!contractGroupDO.getName().contains(name)) {
                    categoryListVOList = categoryListVOList.parallelStream().filter(categoryListVO
                            -> categoryListVO.getName() != null && categoryListVO.getName()
                            .contains(name)).collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(categoryListVOList)) {
                        return null;
                    }
                }
            }
            contractGroupListVO.setCategoryListVOList(categoryListVOList);
            return contractGroupListVO;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }


    @Override
    public int selectCount(CategoryQuery categoryQuery, String siteId) {
        Example example = buildExample(categoryQuery, siteId);
        return categoryDAO.selectCountByExample(example);
    }

    @Override
    public Page<CategoryListVO> selectPage(CategoryQuery categoryQuery, String siteId) {
        Example example = buildExample(categoryQuery, siteId);
        Page<CategoryDO> page = categoryDAO.selectPageByExample(example,
                categoryQuery.getPageNo(),
                categoryQuery.getPageSize());

        return page.to(CategoryListVO.class);
    }

    @Override
    public CategoryDO selectDOById(Long categoryId, String siteId) {
        return listById(categoryId, siteId);
    }

    @Override
    public List<CategoryDO> selectDO(CategoryQuery categoryQuery, String siteId) {
        Example example = buildExample(categoryQuery, siteId);
        return categoryDAO.selectByExample(example);
    }

    @Override
    public List<CategoryDO> selectByGroupId(Long groupId, String siteId) {
        ParamException.notNull(groupId, "groupId不能为空");
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("groupId", groupId);
        return categoryDAO.selectByExample(example);
    }

    /**
     * 分类下是否有合同在签署中
     *
     * @param categoryDO 分类DO
     * @param siteId     站点id
     * @return true or false
     */
    private boolean isCategoryHasContractSigning(CategoryDO categoryDO, String siteId) {
        List<ContractDO> contractList = contractService.selectByCategoryId(categoryDO.getId(), siteId);
        return !CollectionUtils.isEmpty(contractList) &&
                (contractList.stream().anyMatch(contractDO -> categoryDO.getSubjectId().equals(contractDO.getSubjectId())
                        && (ContractConstants.CONTRACT_STATUS_PERSON.equals(contractDO.getStatus())
                        || ContractConstants.CONTRACT_STATUS_ENTERPRISE.equals(contractDO.getStatus()))));
    }

    @Override
    public List<CategoryDO> listBySubjectId(String subjectId, String siteId) {
        ParamException.notNull(subjectId, "业务id不能为空");
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        example.orderBy("gmtCreate").desc();
        return categoryDAO.selectByExample(example);
    }

    @Override
    public Boolean isSealIdUsed(Long sealId, String siteId) {
        ParamException.notNull(sealId, "印章id不能为空");
        ParamException.notNull(siteId, "租户id不能为空");
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("enterpriseSealId", sealId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        return categoryDAO.selectCountByExample(example) > 0;
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public List<CategoryVO> saveIssuedCategory(IssuedCategoryAddDTO issuedCategoryAddDTO, TokenUser tokenUser) {
        List<CategoryVO> categoryVOList = new ArrayList<>();
        List<Long> allCategoryIds = new ArrayList<>();
        for (IssuedCategoryAddDTO.Category category : issuedCategoryAddDTO.getCategoryList()) {
            if (!CollectionUtils.isEmpty(category.getCategoryIds())) {
                allCategoryIds.addAll(category.getCategoryIds());
            }
        }
        // 模板信息
        List<TemplateDO> templateDOList = templateService.selectByCategoryIds(allCategoryIds, tokenUser.getSiteId());
        // 模板按合同Id分组
        Map<Long, List<TemplateDO>> categoryIdListMap = templateDOList.parallelStream()
                .collect(Collectors.groupingBy(TemplateDO::getCategoryId));
        ParamException.notEmpty(issuedCategoryAddDTO.getSubjectList(), "未选择用工单位");
        // 业务Id-name
        Map<String, String> idNameMap = issuedCategoryAddDTO.getSubjectList().parallelStream().collect(Collectors
                .toMap(IssuedCategoryAddDTO.Subject::getSubjectId, IssuedCategoryAddDTO.Subject::getSubjectName, (v1, v2) -> v1));
        // 公司级的统计重复
        StringBuilder subjectError = new StringBuilder();
        for (String subjectId : idNameMap.keySet()) {
            // 查询公司下模板分组是否存在
            List<ContractGroupDO> contractGroupDOList = contractGroupService.selectBySubjectId(subjectId, tokenUser);
            // 模板分组名称-id
            Map<String, Long> contractGroupNameContractGroupIdMap = contractGroupDOList.parallelStream()
                    .collect(Collectors.toMap(ContractGroupDO::getName, BaseDO::getId, (v1, v2) -> v1));
            // 分组的统计重复
            List<String> groupErrorList = new ArrayList<>();
            for (IssuedCategoryAddDTO.Category category : issuedCategoryAddDTO.getCategoryList()) {
                // 下发模板
                List<CategoryDO> categoryDOList = selectByIds(category.getCategoryIds());
                if (CollectionUtils.isEmpty(categoryDOList)) {
                    continue;
                }
                // 公司下没有该分组 创建
                Long contractGroupId = contractGroupNameContractGroupIdMap.get(category.getContractGroupName());
                if (contractGroupId == null) {
                    ContractGroupAddDTO contractGroupAddDTO = new ContractGroupAddDTO();
                    contractGroupAddDTO.setName(category.getContractGroupName());
                    contractGroupAddDTO.setSubjectId(subjectId);
                    ContractGroupVO save = contractGroupService.save(contractGroupAddDTO, tokenUser);
                    contractGroupId = save.getId();
                } else {
                    // 查看分组下是否有同名模板
                    List<CategoryDO> categoryDOS = selectBySubjectIdAndNames(subjectId, category.getContractGroupName()
                            , categoryDOList.parallelStream().map(CategoryDO::getName).collect(Collectors.toList()), tokenUser);
                    // 公司下已存在同名合同
                    deleteByIds(tokenUser, categoryDOS.parallelStream().map(BaseDO::getId).toArray(Long[]::new));
                }
                for (CategoryDO categoryDO : categoryDOList) {
                    CategoryAddDTO categoryAddDTO = categoryDO.to(CategoryAddDTO.class);
                    categoryAddDTO.setSubjectId(subjectId);
                    categoryAddDTO.setGroupId(contractGroupId);
                    if (issuedCategoryAddDTO.getIsSeal() != null
                            && issuedCategoryAddDTO.getIsSeal()
                            && categoryDO.getEnterpriseSealId() != null) {
                        // 同步下发该合同类型的公司印章
                        IssuedSealAddDTO issuedSealAddDTO = new IssuedSealAddDTO();
                        // 公司id
                        List<String> subjectIds = new ArrayList<>();
                        subjectIds.add(subjectId);
                        issuedSealAddDTO.setSubjectIds(subjectIds);
                        // 印章id
                        List<Long> sealIds = new ArrayList<>();
                        sealIds.add(categoryDO.getEnterpriseSealId());
                        issuedSealAddDTO.setCategoryIds(sealIds);
                        List<SealVO> sealVOList = sealService.saveIssuedSeal(issuedSealAddDTO, tokenUser);
                        ParamException.isFalse(CollectionUtils.isEmpty(sealVOList),
                                "下发印章错误！");
                        categoryAddDTO.setEnterpriseSealId(sealVOList.get(0).getId());
                    } else {
                        categoryAddDTO.setEnterpriseSealId(null);
                    }
                    categoryAddDTO.setIssue(true);
                    categoryAddDTO.setSourceId(categoryDO.getId() + "");
                    CategoryVO categoryVO = saveNoLogic(categoryAddDTO, tokenUser);
                    categoryVOList.add(categoryVO);
                    // 合同中的模板
                    List<TemplateDO> categoryTemplateDOList = categoryIdListMap.get(categoryDO.getId());
                    if (!CollectionUtils.isEmpty(categoryTemplateDOList)) {
                        for (TemplateDO templateDO : categoryTemplateDOList) {
                            TemplateAddDTO templateAddDTO = templateDO.to(TemplateAddDTO.class);
                            templateAddDTO.setCategoryId(categoryVO.getId());
                            TemplateVO templateVO = templateService.save(templateAddDTO, tokenUser);
                            // 模板变量
                            List<TemplateVariableDO> templateVariableDOList = templateVariableService
                                    .selectByTemplateId(templateDO.getId(), templateDO.getSiteId());
                            List<TemplateVariableAddDTO> templateVariableAddDTOList = new ArrayList<>();
                            for (TemplateVariableDO templateVariableDO : templateVariableDOList) {
                                TemplateVariableAddDTO templateVariableAddDTO
                                        = templateVariableDO.to(TemplateVariableAddDTO.class);
                                templateVariableAddDTO.setTemplateId(templateVO.getId());
                                templateVariableAddDTOList.add(templateVariableAddDTO);
                            }
                            templateVariableService.batchSave(templateVariableAddDTOList, tokenUser);
                            // 印章位置
                            List<SealPositionDO> sealPositionDOList = sealPositionService
                                    .selectByTemplateId(templateDO.getId(), templateDO.getSiteId());
                            List<SealPositionAddDTO> sealPositionAddDTOList = new ArrayList<>();
                            for (SealPositionDO sealPositionDO : sealPositionDOList) {
                                SealPositionAddDTO sealPositionAddDTO = sealPositionDO.to(SealPositionAddDTO.class);
                                sealPositionAddDTO.setTemplateId(templateVO.getId());
                                sealPositionAddDTOList.add(sealPositionAddDTO);
                            }
                            sealPositionService.batchSave(sealPositionAddDTOList, tokenUser);
                        }
                    }
                }
            }
            if (!CollectionUtils.isEmpty(groupErrorList)) {
                subjectError.append(idNameMap.get(subjectId)).append("公司下的").append(groupErrorList.parallelStream()
                        .collect(Collectors.joining(","))).append(";");
            }
        }
        ParamException.isFalse(StringUtils.hasLength(subjectError.toString()), subjectError.toString());
        return categoryVOList;
    }


    @Override
    public List<CategoryDO> selectBySubjectIdAndNames(String subjectId, String contractGroupName, List<String> names, TokenUser tokenUser) {
        ParamException.notEmpty(names, contractGroupName + "分组下的模板已全部失效，请重新选择");
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andEqualTo("subjectId", subjectId)
                .andIn("name", names);
        return categoryDAO.selectByExample(example);
    }

    @Override
    public List<CategoryDO> selectBySubjectIdsAndNames(List<String> subjectIds, List<String> names, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(subjectIds)) {
            return new ArrayList<>();
        }
        if (CollectionUtils.isEmpty(names)) {
            return new ArrayList<>();
        }
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andIn("subjectId", subjectIds)
                .andIn("name", names);
        return categoryDAO.selectByExample(example);
    }

    @Override
    public List<CategoryDO> selectBySubjectIdsAndEnterpriseSealId(List<String> subjectIds
            , List<Long> enterpriseSealIds, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(subjectIds)) {
            return new ArrayList<>();
        }
        if (CollectionUtils.isEmpty(enterpriseSealIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andIn("subjectId", subjectIds)
                .andIn("enterpriseSealId", enterpriseSealIds);
        return categoryDAO.selectByExample(example);
    }

    @Override
    public void setSealVO(CategoryListVO categoryListVO, TokenUser tokenUser) {
        if (categoryListVO.getEnterpriseSealId() == null) {
            return;
        }
        SealVO sealVO = sealService.selectById(categoryListVO.getEnterpriseSealId(), tokenUser.getSiteId());
        if (sealVO == null || sealVO.getStatus() == null || sealVO.getStatus() != 1) {
            return;
        }
        categoryListVO.setSealVO(sealVO);
    }

    @Override
    public boolean checkTemplate(CategoryListVO categoryListVO, TokenUser tokenUser) {
        // 印章为空  并且  签署方式是双方签署  该合同分类不能发起合同
        if (categoryListVO.getSealVO() == null && SignMethod.BOTH.getValue().equals(categoryListVO.getSignType())) {
            return false;
        }
        // 判断该模板是否设置了印章位置
        List<TemplateDO> templateDOList = templateService.selectByCategoryId(categoryListVO.getId(), tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(templateDOList)) {
            // 没有查询到模板 无法发起合同
            return false;
        }
        TemplateDO templateDO = templateDOList.get(0);
        // 判断该模板是否有内容
        if (StrKit.isEmpty(templateDO.getContent())) {
            // 该模板没有内容 无法发起合同
            return false;
        }
        List<SealPositionDO> sealPositionDOList = sealPositionService.selectByTemplateIdAndAccountType(
                templateDO.getId(), AccountType.PERSON.getValue(), tokenUser.getSiteId());
        // 如果不是企业单方签署,需要判断个人印章位置
        if(!SignMethod.ENTERPRISE_ONLY.getValue().equals(categoryListVO.getSignType())){
            if (CollectionUtils.isEmpty(sealPositionDOList)) {
                // 模板没有设置个人印章位置 无法发起合同
                return false;
            }
        }
        if (SignMethod.BOTH.getValue().equals(categoryListVO.getSignType()) ||
                SignMethod.ENTERPRISE_ONLY.getValue().equals(categoryListVO.getSignType())) {
            // 双方签署和企业单方签署检查是否设置了企业签署位置
            sealPositionDOList = sealPositionService.selectByTemplateIdAndAccountType(
                    templateDO.getId(), AccountType.ENTERPRISE.getValue(), tokenUser.getSiteId());
            if (CollectionUtils.isEmpty(sealPositionDOList)) {
                // 模板没有设置企业印章位置 无法发起合同
                return false;
            }
        }
        return true;
    }

    @Override
    public String checkTemplate(CategoryVO categoryVO, TokenUser tokenUser) {
        // 判断该模板是否设置了印章位置
        List<TemplateDO> templateDOList = templateService.selectByCategoryId(categoryVO.getId(), tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(templateDOList)) {
            // 没有查询到模板 无法发起合同
            return "发起合同出错,错误信息:没有查询到模板";
        }
        TemplateDO templateDO = templateDOList.get(0);
        // 判断该模板是否有内容
        if (StrKit.isEmpty(templateDO.getContent())) {
            // 该模板没有内容 无法发起合同
            return "发起合同出错,错误信息:该模板没有内容";
        }
        List<SealPositionDO> sealPositionDOList = sealPositionService.selectByTemplateIdAndAccountType(
                templateDO.getId(), AccountType.PERSON.getValue(), tokenUser.getSiteId());
        // 企业单方签署不判断个人印章位置
        if(!SignMethod.ENTERPRISE_ONLY.getValue().equals(categoryVO.getSignType())){
            if (CollectionUtils.isEmpty(sealPositionDOList)) {
                // 模板没有设置个人印章位置 无法发起合同
                return "发起合同出错,错误信息:未设置个人默认印章位置";
            }
        }
        if (SignMethod.BOTH.getValue().equals(categoryVO.getSignType()) ||
                SignMethod.ENTERPRISE_ONLY.getValue().equals(categoryVO.getSignType())) {
            // 双方签署或企业单方签署检查是否设置了企业签署位置
            sealPositionDOList = sealPositionService.selectByTemplateIdAndAccountType(
                    templateDO.getId(), AccountType.ENTERPRISE.getValue(), tokenUser.getSiteId());
            if (CollectionUtils.isEmpty(sealPositionDOList)) {
                // 模板没有设置企业印章位置 无法发起合同
                return "发起合同出错,错误信息:未设置企业默认印章位置";
            }
        }
        return null;
    }

    /**
     * 根据查询参数，构建example
     *
     * @param categoryQuery 查询参数
     * @param siteId        所属站点id
     * @return example
     */
    private Example buildExample(CategoryQuery categoryQuery, String siteId) {
        Example example = new Example(CategoryDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        if (categoryQuery.getValid() != null) {
            example.and().andEqualTo("valid", categoryQuery.getValid());
        }
        if (categoryQuery.getGroupId() != null) {
            example.and().andEqualTo("groupId", categoryQuery.getGroupId());
        }
        if (categoryQuery.getSourceId() != null) {
            example.and().andEqualTo("sourceId", categoryQuery.getSourceId());
        }
        if (categoryQuery.getSubjectId() != null) {
            example.and().andEqualTo("subjectId", categoryQuery.getSubjectId());
        }
        if (categoryQuery.getName() != null) {
            example.and().andLike("name", "%" + categoryQuery.getName() + "%");
        }
        if (categoryQuery.getDescription() != null) {
            example.and().andEqualTo("description", categoryQuery.getDescription());
        }
        if (categoryQuery.getRemark() != null) {
            example.and().andLike("remark", "%" + categoryQuery.getRemark() + "%");
        }
        if (categoryQuery.getEnterpriseSealId() != null) {
            example.and().andEqualTo("enterpriseSealId", categoryQuery.getEnterpriseSealId());
        }
        if (categoryQuery.getSignType() != null) {
            example.and().andEqualTo("signType", categoryQuery.getSignType());
        }
        if (categoryQuery.getSignSealType() != null) {
            example.and().andEqualTo("signSealType", categoryQuery.getSignSealType());
        }
        if (categoryQuery.getExpireDays() != null) {
            example.and().andEqualTo("expireDays", categoryQuery.getExpireDays());
        }
        if (categoryQuery.getSignOrder() != null) {
            example.and().andEqualTo("signOrder", categoryQuery.getSignOrder());
        }
        if (categoryQuery.getFileType() != null) {
            example.and().andEqualTo("fileType", categoryQuery.getFileType());
        }
        if (categoryQuery.getAppendixType() != null) {
            example.and().andEqualTo("appendixType", categoryQuery.getAppendixType());
        }
        // 排序
        ExampleKit.setExampleOrder(example, categoryQuery.getOrders());
        return example;
    }
}




